package com.nowcoder.topic.tree.hardest;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Queue;

/**
 * NC146 循环右移二叉树
 * @author d3y1
 */
public class NC146 {
    /**
     * 代码中的类名、方法名、参数名已经指定，请勿修改，直接返回方法规定的值即可
     *
     * @param root TreeNode类
     * @param k int整型
     * @return TreeNode类
     */
    public TreeNode cyclicShiftTree (TreeNode root, int k) {
        return solution(root, k);
    }

    /**
     * 层序遍历
     * @param root
     * @param k
     * @return
     */
    private TreeNode solution(TreeNode root, int k){
        if(root == null){
            return null;
        }

        Queue<QueueNode> queue = new LinkedList<>();
        // level -> count
        HashMap<Integer,Integer> cntMap = new HashMap<>();
        // level+seq -> treeNode
        HashMap<String,TreeNode> treeNodeMap = new HashMap<>();

        // 树的层级 从1开始
        int level = 1;
        // 当前节点 对应父层节点的索引位置 从0开始
        int index = 0;
        // 当前层级 实际节点数目
        int count = 1;
        // 当前层级 实际节点序号(count-1) 从0开始
        int seq = 0;
        queue.offer(new QueueNode(root, level, index, seq));
        cntMap.put(level, count);

        int size,kIdx,upCnt,upSeq,upDirect;
        QueueNode queueNode;
        TreeNode treeNode,upTreeNode;
        while(!queue.isEmpty()){
            size = queue.size();
            level++;
            index = 0;
            count = 0;
            while(size-- > 0){
                queueNode = queue.poll();
                treeNode = queueNode.treeNode;
                // 加入队列
                if(treeNode.left != null){
                    count++;
                    queue.offer(new QueueNode(treeNode.left, level, index, count-1));
                }
                index++;

                if(treeNode.right != null){
                    count++;
                    queue.offer(new QueueNode(treeNode.right, level, index, count-1));
                }
                index++;

                treeNode.left = null;
                treeNode.right = null;
                treeNodeMap.put(queueNode.level+"-"+queueNode.seq, treeNode);

                // 向右循环移动k位
                if(queueNode.level > 1){
                    // 上层(父层) 实际节点数目
                    upCnt = cntMap.get(queueNode.level-1);
                    // 向右循环移动k位 到达的位置索引
                    kIdx = (queueNode.index+k)%(upCnt*2);
                    // 对应的 上层(父层) 节点序号
                    upSeq = kIdx/2;
                    // 判断左右节点
                    upDirect = kIdx%2;
                    // 根据 父层层级+节点序号 找到对应的应该挂载的父节点
                    upTreeNode = treeNodeMap.get((queueNode.level-1)+"-"+upSeq);
                    // 进行挂载
                    if(upDirect == 0){
                        upTreeNode.left = treeNode;
                    }else{
                        upTreeNode.right = treeNode;
                    }
                }
            }
            cntMap.put(level, count);
        }

        return root;
    }

    private class QueueNode{
        TreeNode treeNode;
        int level;
        int index;
        int seq;
        public QueueNode(TreeNode treeNode, int level, int index, int seq){
            this.treeNode = treeNode;
            this.level = level;
            this.index = index;
            this.seq = seq;
        }
    }

    private class TreeNode {
        int val = 0;
        TreeNode left = null;
        TreeNode right = null;

        public TreeNode(int val) {
            this.val = val;
        }
    }
}